package transport;

import network.*;

import java.util.*;

public class Acksend {

	String destName;
	static long timeoutAck = 10000;
	Timer timeout;
	HashMap<Integer, String> hashMsg = new HashMap<Integer, String>();
	int indiceMap = 0;
	int lastReceivedMessage = 0;
	int lastSentMessage = -1;
	long lastSentMessageTime;
	long lastMsgSize = 0;
	AckProgressWindow window;
	
	// friend:myName:HELLOACK: message 0 in queue
	// friend:myName:MESSAGE:number:message-content:
	// myName:friend:ACK:number:
	// friend:myName:ENDACK: no ack required, client will figure it out in case it does not arrive.

	Acksend(String destName, String msg) {
		this.destName = destName;
		window = new AckProgressWindow(destName);
		window.setVisible(true);
		sendOpenAck();
		hashMsg.put(indiceMap, msg);
		indiceMap++;
		sendMsg();
	}

	synchronized void sendOpenAck(){
		hashMsg.put(indiceMap,openAckMessage());
		indiceMap++;
	}
	
	String openAckMessage(){
		StringBuffer buf  = new StringBuffer();
		buf.append(destName).append(":").append(TransportLayer.myID).append(":HELLOACK:");
		return buf.toString();
	}
	
	String endAckMessage(){
		StringBuffer buf  = new StringBuffer();
		buf.append(destName).append(":").append(TransportLayer.myID).append(":ENDACK:");
		return buf.toString();
	}
	
	synchronized void update(String msg) {
		hashMsg.put(indiceMap, msg);
		indiceMap++;
	}

	StringBuffer messageMSG(int num) {
		StringBuffer buf = new StringBuffer();
		buf.append(destName).append(":").append(TransportLayer.myID)
				.append(":").append("MESSAGE").append(":").append(Integer.toString(num))
				.append(":");
		return buf;
	}

	synchronized void sendMsg() {
		if (hashMsg.isEmpty()) {
			NetworkLayer.send(endAckMessage());
			window.setEnded();
			TransportLayer.viderACKsend(destName);
			return;
		}
		timeout = new Timer();
		int n = lastSentMessage + 1;
		String msg = hashMsg.get(n);
		StringBuffer buff = new StringBuffer();
		if(n != 0){ // Si = 0 alors envoi du message d'ouverture de conversation donc pas besoin de :MESSAGE:
			buff = messageMSG(n);
		}
		buff.append(msg);
		sendMessage(buff.toString());
	}

	synchronized void sendMessage(String message) {
		System.out.println("Sending message " + (lastSentMessage + 1));
		//System.out.println(message);
		lastMsgSize = message.length();
		lastSentMessageTime = System.currentTimeMillis();
		NetworkLayer.send(message);
		AckTask task = new AckTask(message);
		timeout.schedule(task, timeoutAck, timeoutAck);
	}

	synchronized void processAck(String message) {
		String[] splitMessage = message.split(":");
		int messageId = Integer.parseInt(splitMessage[3]);
		if (messageId == lastSentMessage + 1) {
			// cancel the resending task
			timeout.cancel();
			hashMsg.remove(lastSentMessage + 1);
			lastSentMessage++;
			window.updateCurrentMessage();
			window.updateLatencyAndSpeed(System.currentTimeMillis()-lastSentMessageTime, lastMsgSize);
			System.out.println("Ack received for message " + lastSentMessage);
			sendMsg();
		}
	}
}